package com.swak.utils;

import java.util.function.Function;

import org.springframework.lang.Nullable;

import com.swak.entity.Result;

/**
 * Functions
 *
 * @author: lifeng
 * @date: 2020/3/29 14:07
 */
public final class Functions {
	private Functions() {
	}

	/**
	 * Returns the False function.
	 */
	public static Function<Object, Boolean> falseFunction() {
		return FalseFunction.INSTANCE;
	}

	private enum FalseFunction implements Function<Object, Boolean> {

		/**
		 * 唯一对象
		 */
		INSTANCE;

		@Override
		public Boolean apply(Object o) {
			return Boolean.FALSE;
		}

		@Override
		public String toString() {
			return "Functions.TrueFunction()";
		}
	}

	/**
	 * Returns the True function.
	 */
	public static Function<Object, Boolean> trueFunction() {
		return TrueFunction.INSTANCE;
	}

	private enum TrueFunction implements Function<Object, Boolean> {

		/**
		 * 唯一对象
		 */
		INSTANCE;

		@Override
		public Boolean apply(Object o) {
			return Boolean.TRUE;
		}

		@Override
		public String toString() {
			return "Functions.TrueFunction()";
		}
	}

	/**
	 * Returns the Result function.
	 */
	public static Function<Object, Result> resultFunction() {
		return ResultFunction.INSTANCE;
	}

	private enum ResultFunction implements Function<Object, Result> {

		/**
		 * 唯一对象
		 */
		INSTANCE;

		@Override
		public Result apply(Object o) {
			return Result.success(o);
		}

		@Override
		public String toString() {
			return "Functions.resultFunction()";
		}
	}

	/**
	 * Returns the identity function.
	 */
	@SuppressWarnings("unchecked")
	public static <E> Function<E, E> identity() {
		return (Function<E, E>) IdentityFunction.INSTANCE;
	}

	private enum IdentityFunction implements Function<Object, Object> {

		/**
		 * 唯一对象
		 */
		INSTANCE;

		@Override
		public Object apply(@Nullable Object o) {
			return o;
		}

		@Override
		public String toString() {
			return "IdentityFunction.identity()";
		}
	}

	@FunctionalInterface
	public interface ThrowableFunction {

		/**
		 * Executes the action
		 *
		 * @throws Throwable if met with error
		 */
		void execute() throws Throwable;

		/**
		 * Executes {@link ThrowableFunction}
		 *
		 * @param action {@link ThrowableFunction}
		 * @throws RuntimeException wrap {@link Exception} to {@link RuntimeException}
		 */
		static void execute(ThrowableFunction action) throws RuntimeException {
			try {
				action.execute();
			} catch (Throwable e) {
				throw new RuntimeException(e);
			}
		}
	}
}
